/*
 * Copyright (C) 2003, Velocityme Partnership
 * UserSessionBean.java
 *
 * Created on 16 April 2003, 09:44
 */

package com.velocityme.session;

import com.velocityme.entity.ChangeDeltaItemTypeBean;
import com.velocityme.entity.ChangeDeltaTypeBean;
import com.velocityme.entity.PermissionBean;
import javax.ejb.*;
import java.util.*;
import javax.naming.*;
import com.velocityme.interfaces.*;
import com.velocityme.utility.DuplicateUserException;
import com.velocityme.utility.InvalidKeyException;
import com.velocityme.utility.PasswordEncrypter;
import com.velocityme.utility.PasswordIncorrectException;
import com.velocityme.utility.PermissionDeniedException;
import com.velocityme.valueobjects.*;
import java.rmi.RemoteException;

/**
 *
 * @author  Robert Crida Work
 * @ejb.bean
 *           type="Stateless"
 *           cmp-version="2.x"
 *           name="UserSession"
 *           jndi-name="ejb/UserSession"
 *           view-type="local"
 *           transaction-type="Container"
 * @ejb.transaction type="Required"
 *
 * @ejb.util generate="physical"
 */
public class UserSessionBean implements SessionBean {
    
    private SessionContext m_context;

    private SearchSessionLocal m_searchSessionLocal;
    
    private PermissionLocal m_permissionUserCreate;
    private PermissionLocal m_permissionUserEdit;
    private PermissionLocal m_permissionUserChangePassword;
    private PermissionLocal m_permissionUserSetEnabled;
    private PermissionLocal m_permissionNodeView;
    
    /**
     * Check  to see if the specified username already exists in the database
     *
     * @param p_username The username to check the database for
     * @return true if the username already exists
     **/
    public boolean isUsernameAlreadyUsed(String p_username) throws NamingException {
        try {
            UserUtil.getLocalHome().findByUsername(p_username);
        }
        catch(FinderException e) {
            return false;
        }
        return true;
    }

    /**
     * If the user has permission to create a new User in the specified parent
     * node then go ahead and create it and log an appropriate ChangeDelta.
     *
     * @param p_key User's security key
     * @param p_parentNode The node which will contain the new User
     * @param p_userValue The value details for the User part of the user
     *
     * @ejb.interface-method view-type="local"
     **/
    public UserLocal createUser(KeySessionLocal p_keyLocal,
                                NodeLocal p_parentNodeLocal,
                                com.velocityme.valueobjects.UserValue p_userValue,
                                java.lang.String p_password)
        throws PermissionDeniedException, InvalidKeyException, DuplicateUserException {
        try {
            if (m_searchSessionLocal.getAssignedPermissionsLocal(p_keyLocal, p_parentNodeLocal).contains(m_permissionUserCreate)) {
                if (isUsernameAlreadyUsed(p_userValue.getUserName()))
                    throw new DuplicateUserException();
                p_userValue.getNodeValue().setType("User");
                p_userValue.getNodeValue().setFinalType("User");
                p_userValue.setIsEnabled(Boolean.FALSE);
                DBObjectLocal dBObjectLocal = DBObjectUtil.getLocalHome().create();
                NodeValue nodeValue = p_userValue.getNodeValue();
                nodeValue.setName(p_userValue.getUserName());
                PersonValue personValue = p_userValue.getPersonValue();
                NodeLocal nodeLocal = NodeUtil.getLocalHome().create(dBObjectLocal, nodeValue, p_parentNodeLocal);
                nodeValue.setNodeId(nodeLocal.getNodeId());
                UserLocal userLocal = UserUtil.getLocalHome().create(nodeLocal, p_userValue);
                userLocal.setPassword(PasswordEncrypter.getInstance().encrypt(p_password));
                ChangeDeltaLocal changeDeltaLocal = ChangeDeltaUtil.getLocalHome().create(new Date(), ChangeDeltaTypeBean.CREATE, p_keyLocal.getUserLocal(), dBObjectLocal);
                changeDeltaLocal.addItem(ChangeDeltaItemTypeBean.USERNAME, p_userValue.getUserName());
                changeDeltaLocal.addItem(ChangeDeltaItemTypeBean.DESCRIPTION, nodeValue.getDescription());
                changeDeltaLocal.addItem(ChangeDeltaItemTypeBean.PERSON, personValue.getContactableValue().getNodeValue().getName());
                changeDeltaLocal.addItem(ChangeDeltaItemTypeBean.PARENT_NODE, p_parentNodeLocal.getPathName());
                return userLocal;
            }
            else
                throw new PermissionDeniedException();
        }
        catch(NamingException e) {
            throw new EJBException(e);
        }
        catch(CreateException e) {
            throw new EJBException(e);
        }
        catch(com.velocityme.interfaces.ServiceUnavailableException e) {
            throw new EJBException(e);
        }
    }
    
    /**
     * If the user has permission to edit the user then do so and log the
     * changes with an appropriate ChangeDelta.
     *
     * @param p_key User's security key
     * @param p_user The User object being editted
     * @param p_userValue The value details for the User part of the user
     *
     * @ejb.interface-method view-type="local"
     **/
    public void editUser(KeySessionLocal p_keyLocal,
                         UserLocal p_userLocal,
                         com.velocityme.valueobjects.UserValue p_userValue)
        throws PermissionDeniedException, InvalidKeyException, DuplicateUserException {
        try {
            NodeLocal nodeLocal = p_userLocal.getNodeLocal();
            if (m_searchSessionLocal.getAssignedPermissionsLocal(p_keyLocal, nodeLocal).contains(m_permissionUserEdit)) {
                if (!p_userValue.getUserName().equals(p_userLocal.getUserName()) && isUsernameAlreadyUsed(p_userValue.getUserName()))
                    throw new DuplicateUserException();
                p_userValue.setIsEnabled(p_userLocal.getIsEnabled());
                NodeValue nodeValue = p_userValue.getNodeValue();
                PersonValue personValue = p_userValue.getPersonValue();
                ChangeDeltaLocal changeDeltaLocal = ChangeDeltaUtil.getLocalHome().create(new Date(), ChangeDeltaTypeBean.EDIT, p_keyLocal.getUserLocal(), nodeLocal.getDBObjectLocal());
                if (!p_userValue.getUserName().equals(p_userLocal.getUserName()))
                    changeDeltaLocal.addItem(ChangeDeltaItemTypeBean.USERNAME, p_userValue.getUserName());
                if (!nodeValue.getDescription().equals(nodeLocal.getDescription()))
                    changeDeltaLocal.addItem(ChangeDeltaItemTypeBean.DESCRIPTION, nodeValue.getDescription());
                if (!p_userLocal.getPersonLocal().getPersonId().equals(personValue.getPersonId()))
                    changeDeltaLocal.addItem(ChangeDeltaItemTypeBean.PERSON, personValue.getContactableValue().getNodeValue().getName());
                nodeLocal.setNodeValue(nodeValue);
                p_userLocal.setUserValue(p_userValue);
            }
            else
                throw new PermissionDeniedException();
        }
        catch(NamingException e) {
            throw new EJBException(e);
        }
        catch(CreateException e) {
            throw new EJBException(e);
        }
    }
    
    /**
     * If the user has permission to access a user then return the local object.
     *
     * @param p_key User's security key
     * @param p_actionPK The User object to lookup
     *
     * @ejb.interface-method view-type="local"
     **/
    public UserLocal getUserLocal(KeySessionLocal p_keyLocal, 
                                  UserPK p_userPK)
        throws PermissionDeniedException, InvalidKeyException {
        try {
            UserLocal userLocal = UserUtil.getLocalHome().findByPrimaryKey(p_userPK);
            NodeLocal nodeLocal = userLocal.getNodeLocal();
            if (m_searchSessionLocal.getAssignedPermissionsLocal(p_keyLocal, nodeLocal).contains(m_permissionNodeView)) {
                return userLocal;
            }
            else
                throw new PermissionDeniedException();
        }
        catch(NamingException e) {
            throw new EJBException(e);
        }
        catch(FinderException e) {
            throw new EJBException(e);
        }
    }
    
    /**
     * If the user has permission to change the passwrod then do so and log the
     * change with an appropriate ChangeDelta.
     *
     * @param p_key User's security key
     * @param p_user The User object being editted
     * @param p_oldPassword The current password
     * @param p_newPassword The new password
     *
     * @ejb.interface-method view-type="local"
     **/
    public void changePassword(KeySessionLocal p_keyLocal,
                               UserLocal p_userLocal,
                               String p_oldPassword,
                               String p_newPassword)
        throws PermissionDeniedException, InvalidKeyException, PasswordIncorrectException {
        try {
            NodeLocal nodeLocal = p_userLocal.getNodeLocal();
            String newEncrypted = PasswordEncrypter.getInstance().encrypt(p_newPassword);
            if (m_searchSessionLocal.getAssignedPermissionsLocal(p_keyLocal, nodeLocal).contains(m_permissionUserChangePassword)) {
                p_userLocal.setPassword(newEncrypted);
                ChangeDeltaLocal changeDeltaLocal = ChangeDeltaUtil.getLocalHome().create(new Date(), ChangeDeltaTypeBean.SET_PASSWORD, p_keyLocal.getUserLocal(), nodeLocal.getDBObjectLocal());
            }
            else 
                if (p_userLocal.equals(p_keyLocal.getUserLocal())) {
                    String oldEncrypted = PasswordEncrypter.getInstance().encrypt(p_oldPassword);
                    if (oldEncrypted.equals(p_userLocal.getPassword())) {
                        p_userLocal.setPassword(newEncrypted);
                        ChangeDeltaLocal changeDeltaLocal = ChangeDeltaUtil.getLocalHome().create(new Date(), ChangeDeltaTypeBean.SET_PASSWORD, p_keyLocal.getUserLocal(), nodeLocal.getDBObjectLocal());
                    }
                    else
                        throw new PasswordIncorrectException();
                }
                else
                    throw new PermissionDeniedException();
        }
        catch(NamingException e) {
            throw new EJBException(e);
        }
        catch(CreateException e) {
            throw new EJBException(e);
        }
        catch(com.velocityme.interfaces.ServiceUnavailableException e) {
            throw new EJBException(e);
        }
    }
    
    /**
     * If the user has permission to enable a user then do so and log the
     * change with an appropriate ChangeDelta.
     *
     * @param p_key User's security key
     * @param p_user The User object being editted
     * @param p_enabled The new enabled status
     *
     * @ejb.interface-method view-type="local"
     **/
    public void setEnabled(KeySessionLocal p_keyLocal,
                           UserLocal p_userLocal,
                           Boolean p_enabled)
        throws PermissionDeniedException, InvalidKeyException {
        try {
            NodeLocal nodeLocal = p_userLocal.getNodeLocal();
            if (m_searchSessionLocal.getAssignedPermissionsLocal(p_keyLocal, nodeLocal).contains(m_permissionUserSetEnabled)) {
                if (!p_userLocal.getIsEnabled().equals(p_enabled)) {
                    ChangeDeltaLocal changeDeltaLocal = ChangeDeltaUtil.getLocalHome().create(new Date(), ChangeDeltaTypeBean.EDIT, p_keyLocal.getUserLocal(), nodeLocal.getDBObjectLocal());
                    changeDeltaLocal.addItem(ChangeDeltaItemTypeBean.ENABLED, p_enabled.toString());
                    p_userLocal.setIsEnabled(p_enabled);
                }
            }
            else 
                throw new PermissionDeniedException();
        }
        catch(NamingException e) {
            throw new EJBException(e);
        }
        catch(CreateException e) {
            throw new EJBException(e);
        }
    }
    
    /**
     * If the user has a valid login key then add a bookmark node.
     *
     * @param p_key User's security key
     * @param p_node The node to be bookmarked
     *
     * @ejb.interface-method view-type="local"
     **/
    public void addBookmarkNode(KeySessionLocal p_keyLocal,
                             NodeLocal p_nodeLocal)
        throws InvalidKeyException {
        if (p_keyLocal.isValid())
            p_keyLocal.getUserLocal().getBookmarkNodesLocal().add(p_nodeLocal);
        else
            throw new InvalidKeyException();
    }
    
    /**
     * If the user has a valid login key then remove a bookmark node.
     *
     * @param p_key User's security key
     * @param p_node The node to be bookmarked
     *
     * @ejb.interface-method view-type="local"
     **/
    public void removeBookmarkNode(KeySessionLocal p_keyLocal,
                                   NodeLocal p_nodeLocal)
        throws InvalidKeyException {
        if (p_keyLocal.isValid())
            p_keyLocal.getUserLocal().getBookmarkNodesLocal().remove(p_nodeLocal);
        else
            throw new InvalidKeyException();
    }
    
    /**
     * Get the full list of user value objects.
     *
     * @param p_key User's security key
     *
     * @ejb.interface-method view-type="local"
     **/
    public java.util.Collection getAllValueObjects(KeySessionLocal p_keyLocal) throws InvalidKeyException {
        Collection values = new java.util.ArrayList();
        try {
            if (p_keyLocal.isValid()) {
                Collection users = UserUtil.getLocalHome().findAll();
                Iterator i = users.iterator();
                while(i.hasNext()) {
                    UserLocal userLocal = (UserLocal)i.next();
                    values.add(new UserValueToString(userLocal.getUserValue()));
                }
            }
            else
                throw new InvalidKeyException();
        }
        catch(NamingException e) {
            throw new EJBException(e);
        }
        catch(FinderException e) {
            throw new EJBException(e);
        }
        return values;
    }
    
    /**
     * Create the Session Bean.
     * @throws CreateException 
     */
    public void ejbCreate() throws CreateException {
        try {
            m_searchSessionLocal = SearchSessionUtil.getLocalHome().create();
            m_permissionUserCreate = PermissionUtil.getLocalHome().findByPrimaryKey(new PermissionPK(new Integer(PermissionBean.USER_CREATE)));
            m_permissionUserEdit = PermissionUtil.getLocalHome().findByPrimaryKey(new PermissionPK(new Integer(PermissionBean.USER_EDIT)));
            m_permissionUserChangePassword = PermissionUtil.getLocalHome().findByPrimaryKey(new PermissionPK(new Integer(PermissionBean.USER_CHANGE_PASSWORD)));
            m_permissionUserSetEnabled = PermissionUtil.getLocalHome().findByPrimaryKey(new PermissionPK(new Integer(PermissionBean.USER_ENABLE)));
            m_permissionNodeView = PermissionUtil.getLocalHome().findByPrimaryKey(new PermissionPK(new Integer(PermissionBean.NODE_VIEW)));
        }
        catch(NamingException e) {
            throw new CreateException(e.getMessage());
        }
        catch(FinderException e) {
            throw new CreateException(e.getMessage());
        }
    }

    public void ejbActivate() throws java.rmi.RemoteException {
    }
    
    public void ejbPassivate() throws java.rmi.RemoteException {
    }
    
    public void ejbRemove() throws java.rmi.RemoteException {
    }
    
    public void setSessionContext(javax.ejb.SessionContext sessionContext) throws java.rmi.RemoteException {
        m_context = sessionContext;
    }
    
}
